﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using StockFinder.StockLists;
using StockFinder.StockLists.Indexes;
using StockFinder.YahooFinance;
using StockFinder.Indicators.Day.ClosePrice;
using StockFinder.Model.Constants;
using StockFinder.GoogleFinance;
using StockFinder.Model;
using System.IO;
using log4net;

namespace StockFinder.Applications.DadRsi
{
    public partial class MainForm : Form
    {
        private static readonly ILog _Log = LogManager.GetLogger(typeof(MainForm));

        public MainForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (_ExchangesCheckBoxList.CheckedItems.Count == 0)
            {
                MessageBox.Show(@"Must select at least one exchange");
            }
            else
            {
                button1.Enabled = false;

                _Log.DebugFormat("Setting up filter");

                var filter = new FilterCriteria();

                _Log.DebugFormat("Price extractor...");

                //1 get price extractor
                if (_PriceSourceDropDownList.SelectedIndex == 0)
                {
                    filter.HistoricDailyPricesExtractor = new GoogleFinanceOnlineStockPriceHistoryExtractor();
                }
                else
                {
                    filter.HistoricDailyPricesExtractor = new YahooFinanceOnlineStockPriceHistoryExtractor();
                }

                _Log.DebugFormat("Stock index lists...");

                //2 get exchange list
                filter.ExchangeLists = new List<IStockList>();
                foreach (var item in _ExchangesCheckBoxList.CheckedItems)
                {
                    filter.ExchangeLists.Add(item as IStockList);
                }

                _Log.DebugFormat("RSI lookback...");

                //3 rsi oversold level
                filter.RsiLookbackPeriod = (int)_RSILookbackPeriodNumericUpDown.Value;

                _Log.DebugFormat("Price history in years..");

                //4 price history lookback in years
                filter.PriceHistoryLookbackInYears = (int)_PriceHistoryInYearsNumericUpDown.Value;

                _Log.DebugFormat("RSI oversold");

                //5 rsi oversold level
                filter.RsiOversoldLevel = _RSIOversoldFilterNumericUpDown.Value;

                _Log.DebugFormat("Percent off high...");

                //6 price percent off high level
                filter.PercentOffHigh = _PriceOversoldFilterNumericUpDown.Value;

                _Log.DebugFormat("Starting background worker...");

                //run worker
                _BackgroundWorker.RunWorkerAsync(filter);
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {

            _ExchangesCheckBoxList.Items.Add(new TelegraphOnlineFtse100StockList() { LoadPrices = false }, true);
            _ExchangesCheckBoxList.Items.Add(new TelegraphOnlineFtse250StockList() { LoadPrices = false }, true);
            _ExchangesCheckBoxList.Items.Add(new FinvizOnlineDowJonesStockList() { LoadPrices = false }, true);
            _ExchangesCheckBoxList.Items.Add(new FinvizOnlineSnP500StockList() { LoadPrices = false }, true);

            _PriceSourceDropDownList.SelectedIndex = 0;
        }

        private void _BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            _BackgroundWorker.ReportProgress(0, "Initializing...");

            var filter = e.Argument as FilterCriteria;

            StringBuilder output = new StringBuilder();            

            output.AppendLine("Symbol,RSI,%offHigh,Index,PassedFilter");

            string indicatorName = string.Format("RSI_{0}", filter.RsiLookbackPeriod);

            _Log.DebugFormat("RSI: {0}", indicatorName);

            var rsi = new ExponentialMovingAverageWilderRelativeStrengthIndexClosePriceDayIndicator(filter.RsiLookbackPeriod,indicatorName);

            bool anyPassedFilter = true;

            _Log.DebugFormat("Looping stock index lists...");            

            foreach (var exchangeList in filter.ExchangeLists)
            {
                _Log.DebugFormat("{0}", exchangeList.Name);

                int iteration = 0;

                _BackgroundWorker.ReportProgress(0, string.Format("Getting {0} stocks...", exchangeList.Name));                

                try
                {
                    _Log.DebugFormat("Getting symbols from list");

                    var symbolsCount = exchangeList.Count;

                    _Log.DebugFormat("{0} symbols", symbolsCount);

                    foreach (var symbol in exchangeList)
                    {
                        iteration++;

                        _Log.DebugFormat("Getting prices for {0}", symbol.Name);

                        var prices = filter.HistoricDailyPricesExtractor.GetHistoricPrices(
                            symbol,
                            DateTime.Today.AddYears(-filter.PriceHistoryLookbackInYears),
                            DateTime.Today);

                        if (prices == null)
                        {
                            _Log.WarnFormat("Prices is null");
                        }
                        else
                        {
                            if (prices.Count > 0)
                            {
                                _Log.DebugFormat("Applying Rsi");

                                rsi.ApplyIndicator(prices);

                                var price = prices.First();

                                _Log.DebugFormat("Getting highest close");

                                var highestClose = prices.Max(p => p.AdjustedClose);

                                _Log.DebugFormat("Calculating percent off high");

                                var percentOffHigh = ((highestClose - price.AdjustedClose) / highestClose) * 100;

                                _Log.DebugFormat("Applying filter");

                                try
                                {
                                    bool passedFilter = percentOffHigh >= filter.PercentOffHigh &&
                                    price.DayIndicators[indicatorName] < filter.RsiOversoldLevel;

                                    //passed filter
                                    output.AppendLine(string.Format("{0},{1},{2},{3},{4}",
                                        symbol.Name,
                                        Math.Round(price.DayIndicators[indicatorName], 2), //rsi 20
                                        Math.Round(percentOffHigh, 2), //% off high
                                        exchangeList.Name,
                                        passedFilter.ToString()));
                                }
                                catch (Exception exception)
                                {
                                    _Log.Error(exception.ToString());                                    
                                }
                                

                                //if (percentOffHigh >= filter.PercentOffHigh &&
                                //    price.DayIndicators[indicatorName] < filter.RsiOversoldLevel)
                                //{
                                //    _Log.DebugFormat("Passed filter");

                                //    anyPassedFilter = true;

                                //    //passed filter
                                //    output.AppendLine(string.Format("{0},{1},{2},{3}",
                                //        symbol.Name,
                                //        Math.Round(price.DayIndicators[indicatorName], 2), //rsi 20
                                //        Math.Round(percentOffHigh, 2), //% off high
                                //        exchangeList.Name));
                                //}                                
                            }
                            else
                            {
                                _Log.WarnFormat("Returned empty price list");
                            }
                        }

                        var progress = ((decimal)iteration / symbolsCount) * 100;
                        var text = string.Format("{0}...{1}", exchangeList.Name, symbol.Name);

                        _BackgroundWorker.ReportProgress(Convert.ToInt32(progress), text);
                    }
                }
                catch (Exception exception)
                {
                    _Log.ErrorFormat(exception.ToString());
                }                
            }

            if (anyPassedFilter)
            {
                e.Result = output.ToString();
            }
        }

        private void _BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {            
            _ProgressBar.Value = 0;
            _ProgressLabel.Text = "Finished";

            if (e.Result != null)
            {
                if (_SaveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        File.WriteAllText(_SaveFileDialog.FileName, e.Result.ToString());
                    }
                    catch (Exception exception)
                    {
                        _Log.ErrorFormat(exception.ToString());                        
                    }                    
                }
            }
            else
            {
                _ProgressLabel.Text = "No stocks passed filter";
            }

            button1.Enabled = true;
        }

        private void _BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            _ProgressBar.Value = e.ProgressPercentage;
            _ProgressLabel.Text = e.UserState.ToString();
        }
    }
}
